﻿using System;
using System.Net;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Threading;
using System.Diagnostics;

namespace iReaper.IndexBuilder.WWESource
{
    public class WWECategoryCrawler
    {
        private int _iFlag;
        private AutoResetEvent _completEvent;
        private bool _isRunning;

        private void Init()
        {
            _iFlag = 0;
            _completEvent = new AutoResetEvent(false);
            _isRunning = true;
        }

        public void Process(ChannelInfo[] infos)
        {
            if (null == infos)
            {
                throw new ArgumentNullException("infos");
            }

            if (_isRunning)
            {
                throw new ApplicationException("This crawler is in use.");
            }

            Init();
            int i = 0;
            foreach (ChannelInfo info in infos)
            {
                foreach (ChannelInfoItem item in info.Items)
                {
                    Console.Write("{0} catories issued\r", i++);
                    WebClient client = new WebClient();
                    client.Encoding = System.Text.Encoding.UTF8;
                    client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(OnPageBack);
                    Interlocked.Increment(ref _iFlag);
                    client.DownloadStringAsync(new Uri(item.Url + "?tab=webcasts&id=odall"), item);
                }
            }

            if (i > 0)
            {
                _completEvent.WaitOne();
            }
        }

        private void OnPageBack(object sender, DownloadStringCompletedEventArgs e)
        {
            try
            {
                ChannelInfoItem channelItem = e.UserState as ChannelInfoItem;

                if (e.Cancelled || e.Error != null)
                {
                    return;
                }
                string content = e.Result;
                Sgml.SgmlReader reader = new Sgml.SgmlReader();
                reader.InputStream = new StringReader(content);

                string xml = reader.ReadOuterXml();
                XmlDocument xmldoc = new XmlDocument();
                xmldoc.LoadXml(xml);

                XmlNodeList nHrefDivs = xmldoc.SelectNodes(".//div[@class='eventList']");

                #region parse single href
                foreach (XmlNode nHrefDiv in nHrefDivs)
                {
                    // Get date time
                    XmlNodeList nPNodeList = nHrefDiv.SelectNodes("./p");
                    EventItem item = new EventItem();
                    foreach (XmlNode pNode in nPNodeList)
                    {
                        XmlNode nTarget = null;
                        // Url and title
                        if ((nTarget = pNode.SelectSingleNode(".//a")) != null)
                        {
                            // Url
                            XmlAttribute xaHref = nTarget.Attributes[0];
                            Debug.Assert(xaHref.Name.ToLower() == "href");
                            string href = xaHref.Value;
                            href = System.Web.HttpUtility.HtmlDecode(href);
                            string title = nTarget.InnerText.Trim();
                            Uri uri = new Uri(href, UriKind.RelativeOrAbsolute);
                            if (uri.IsAbsoluteUri)
                            {
                                // We don't process items does not need msevents.microsoft.com
                                continue;
                            }
                            uri = new Uri(Common.MSFT, uri);
                            item.DetailUrl = uri.AbsoluteUri;

                            item.Title = nTarget.InnerText;
                            channelItem.Events.Add(item);
                        }
                        // DateTime
                        else if ((nTarget = pNode.SelectSingleNode("text()")) != null)
                        {
                            string date = nTarget.OuterXml;
                            DateTime dt;
                            if (DateTime.TryParse(date, out dt))
                            {
                                item.Publish = dt;
                            }
                            else
                            {
                                item.Publish = DateTime.MinValue;
                            }
                        }
                    }
                }
                #endregion

            }
            catch // I can only process what I can.
            {
                return;
            }
            finally
            {
                int flag = Interlocked.Decrement(ref _iFlag);
                if (flag == 0)
                {
                    // Complete this batch
                    _completEvent.Set();
                    _isRunning = false;
                }
            }
        }
    }
}
